package com.yang.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.common.net.HttpHeaders;
import com.yang.common.PageQuery;
import com.yang.entity.dto.PatientDTO;
import com.yang.entity.enumeration.RegionEnum;
import com.yang.entity.vo.PatientVO;
import com.yang.entity.vo.RegionVO;
import com.yang.mapper.PatientMapper;
import com.yang.service.PatientService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Slf4j
public class PatientServiceImpl implements PatientService {

    @Autowired
    private PatientMapper patientMapper;

    // 照片临时存储目录
    @Value("${file.upload.temp-dir}")
    private String tempDir;

    // 照片最终存储目录
    @Value("${file.upload.final-dir}")
    private String finalDir;

    /**
     * 病人信息分页查询
     * @param pageQuery
     * @return
     */
    @Override
    public PageInfo<PatientVO> pageQuery(PageQuery<PatientDTO> pageQuery) {
        PatientDTO params = pageQuery.getParams();
        params.setIsDeleted(0);
        PageHelper.startPage(pageQuery.getPageNum(), pageQuery.getPageSize());
        List<PatientVO> result = patientMapper.getList(params);
        if (CollectionUtils.isNotEmpty(result)) {
            return new PageInfo<>(result);
        }
        return new PageInfo<>(Collections.emptyList());
    }

    /**
     * 根据主键查询病人信息
     * @param id
     * @return
     */
    @Override
    public PatientVO getById(String id) {
        return patientMapper.getById(id);
    }

    /**
     * 新增病人信息
     * @param patientDTO
     * @return
     * @throws IOException
     */
    @Override
    public int add(PatientDTO patientDTO) throws IOException {
        String id = UUID.randomUUID().toString().replace("-", "");
        patientDTO.setId(id);
        if (StringUtils.isNotEmpty(patientDTO.getPhotoName())) {
            // 移动临时图片到正式目录
            moveToFinalDirectory(patientDTO.getPhotoName());
        }
        int insert = patientMapper.insert(patientDTO);
        if (insert == 1) {
            log.info("新增病人信息成功");
        } else {
            log.error("新增病人信息失败");
        }
        return insert;
    }

    /**
     * 将照片由临时文件夹移动到最终文件夹中
     * @param uuidFilename 照片名称
     * @throws IOException
     */
    private void moveToFinalDirectory(String uuidFilename) throws IOException {
        Path tempPath = Paths.get(tempDir).resolve(uuidFilename);
        Path finalPath = Paths.get(finalDir).resolve(uuidFilename);

        // 确保目标目录存在
        Files.createDirectories(finalPath.getParent());

        // 移动文件（原子操作）
        Files.move(tempPath, finalPath, StandardCopyOption.REPLACE_EXISTING);
    }

    /**
     * 修改病人信息
     * @param patientDTO
     * @return
     */
    @Override
    public int update(PatientDTO patientDTO) {
        if (StringUtils.isNotEmpty(patientDTO.getPhotoName())) {
            // 说明本次更新有照片更新，需要将图片由临时目录移动到最终目录
            // 移动文件（原子操作）
            try {
                moveToFinalDirectory(patientDTO.getPhotoName());
            } catch (IOException e) {
                log.error("移动照片发生异常, {}", e.getMessage());
            }
        }
        int update = patientMapper.update(patientDTO);
        if (update == 1) {
            log.info("修改病人信息成功");
        } else {
            log.error("修改病人信息失败");
        }
        return update;
    }

    /**
     * 删除病人信息
     * @param id
     * @return
     */
    public int delete(String id) {
        PatientDTO patientDTO = new PatientDTO();
        patientDTO.setId(id);
        patientDTO.setIsDeleted(1);
        int delete = patientMapper.update(patientDTO);
        if (delete == 1) {
            log.info("删除病人信息成功");
        } else {
            log.error("删除病人信息失败");
        }
        return delete;
    }

    /**
     * 获取人体部位
     * @return
     */
    @Override
    public List<RegionVO> getRegionList() {
        return Arrays.stream(RegionEnum.values())
                .map(item -> new RegionVO(
                        item.getRegionCode(),
                        item.getRegionName()
                )).collect(Collectors.toList());
    }

    /**
     * 上传图片并返回UUID文件名
     * @param file
     * @return
     */
    @Override
    public String uploadPhoto(MultipartFile file) {
        try {
            // 生成UUID文件名（如：a1b2c3d4.jpg）
            String originalFilename = file.getOriginalFilename();
            String photoExtension = originalFilename.substring(originalFilename.lastIndexOf("."));// 获取图片后缀名
            String uuidPhotoName = UUID.randomUUID() + photoExtension;// 拼接UUID+后缀名，构成新图片名称

            // 保存到临时目录
            Path tempPath = Paths.get(tempDir).resolve(uuidPhotoName);
            Files.createDirectories(tempPath.getParent());
            Files.copy(file.getInputStream(), tempPath, StandardCopyOption.REPLACE_EXISTING);

            return uuidPhotoName;
        } catch (IOException e) {
            log.error("照片上传失败: {}", e.getMessage());
        }
        return "";
    }

    /**
     * 根据照片名称获取照片
     * @param photoName
     * @param response
     */
    @Override
    public void getPhoto(String photoName, HttpServletResponse response) {
        log.info("查看照片请求, 照片名称: {}", photoName);

        try {
            // 1. 安全校验（防止路径遍历攻击）
            if (!isValidPhotoName(photoName)) {
                log.error("文件名不合法: {}", photoName);
                response.sendError(400, "非法文件名");
                return;
            }

            // 2.构建完整文件路径
            Path filePath = Paths.get(finalDir, photoName).normalize();
            File imageFile = filePath.toFile();

            // 3.检查文件是否存在
            if (!imageFile.exists() || !imageFile.isFile()) {
                response.sendError(404, "文件不存在");
                return;
            }

            // 4.设置响应头
            response.setContentType(determineContentType(photoName));
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + photoName + "\"");

            // 5.流式传输文件
            try (InputStream in = new FileInputStream(imageFile)) {
                FileCopyUtils.copy(in, response.getOutputStream());
            }
        } catch (FileNotFoundException e) {
            response.setStatus(404);
        } catch (Exception e) {
            response.setStatus(500);
        }
    }

    /**
     * 校验文件名合法性
     * @param fileName
     * @return
     */
    private boolean isValidPhotoName(String fileName) {
        // 允许字母、数字、下划线、短横线和点，且扩展名为图片格式
        return fileName != null &&
                fileName.matches("^[a-zA-Z0-9_\\-]+\\.(jpg|jpeg|png|gif)$") &&
                !fileName.contains("..");
    }

    /**
     * 根据文件后缀名确定Content-Type
     * @param fileName
     * @return
     */
    private String determineContentType(String fileName) {
        String extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
        switch (extension) {
            case "jpg" :
            case "jpeg" :
                return "image/jpeg";
            case "png" :
                return "image/png";
            case "gif" :
                return "image/gif";
            default :
                return "application/octet-stream";
        }
    }

}
